package com.yjha.lzmarathonsys.service.impl;

import com.alibaba.excel.metadata.data.CommentData;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yjha.lzmarathonsys.bean.*;
import com.yjha.lzmarathonsys.config.RabbitmqConfig;
import com.yjha.lzmarathonsys.dto.CommentDto;
import com.yjha.lzmarathonsys.enums.RedisKeyEnum;
import com.yjha.lzmarathonsys.mapper.TbCommentMapper;
import com.yjha.lzmarathonsys.service.*;
import com.yjha.lzmarathonsys.utils.JwtUtils;
import com.yjha.lzmarathonsys.utils.PageUtils;
import com.yjha.lzmarathonsys.utils.Query;
import com.yjha.lzmarathonsys.utils.R;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service("tbCommentService")
public class TbCommentServiceImpl extends ServiceImpl<TbCommentMapper, TbComment> implements TbCommentService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private DefaultRedisScript<Long> auditScript; // 注入Lua脚本Bean

    @Autowired
    private TbUserInfoService tbUserService;

    @Autowired
    private TbPersonClockinService tbPersonClockinService;
    @Autowired
    private TbSpecialClockinService tbSpecialClockinService;

    @Autowired
    private TbImageslService tbImageslService;

    @Autowired
    private TbSpecialService tbSpecialService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<TbComment> tbCommentQueryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(params.get("key").toString())){
            tbCommentQueryWrapper.like("tb_content", "%"+params.get("key").toString()+"%");
        }
        // 基础分页查询
        IPage<TbComment> page = this.page(
                new Query<TbComment>().getPage(params),
                tbCommentQueryWrapper
                        .eq("tb_target_status", 0)
                        .orderByDesc("tb_create_time")
        );

        if (page.getRecords().isEmpty()) {
            return new PageUtils(page);
        }

        // 预加载所有关联数据
        preloadAssociations(page.getRecords());

        return new PageUtils(page);
    }

    private void preloadAssociations(List<TbComment> comments) {
        // 批量加载用户信息
        Map<String, TbUserInfo> userMap = batchLoadUserInfo(comments);

        // 分类处理不同类型的数据
        List<TbComment> type0Comments = comments.stream()
                .filter(c -> c.getTbType() == 0)
                .collect(Collectors.toList());

        List<TbComment> type1Comments = comments.stream()
                .filter(c -> c.getTbType() == 1)
                .collect(Collectors.toList());

        // 并行处理不同类型数据
        CompletableFuture<Void> type0Future = CompletableFuture.runAsync(() ->
                processType0Comments(type0Comments));

        CompletableFuture<Void> type1Future = CompletableFuture.runAsync(() ->
                processType1Comments(type1Comments));

        // 等待所有任务完成
        CompletableFuture.allOf(type0Future, type1Future).join();

        // 设置用户信息
        comments.forEach(comment ->
                comment.setTbUserInfo(userMap.get(comment.getTbUserId())));
    }

    private Map<String, TbUserInfo> batchLoadUserInfo(List<TbComment> comments) {
        Set<String> userIds = comments.stream()
                .map(TbComment::getTbUserId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        if (userIds.isEmpty()) {
            return Collections.emptyMap();
        }

        return tbUserService.list(new QueryWrapper<TbUserInfo>()
                        .in("tb_wxuuid", userIds))
                .stream()
                .collect(Collectors.toMap(TbUserInfo::getTbWxuuid, Function.identity()));
    }

    private void processType0Comments(List<TbComment> comments) {
        if (comments.isEmpty()) return;

        // 批量获取打卡记录
        Map<Integer, TbPersonClockin> clockinMap = batchLoadPersonClockins(comments);

        // 批量加载图片
        Map<String, List<TbImagesl>> imagesMap = batchLoadPersonImages(
                clockinMap.values().stream()
                        .map(TbPersonClockin::getTbUuid)
                        .collect(Collectors.toList())
        );

        // 关联数据
        comments.forEach(comment -> {
            TbPersonClockin clockin = clockinMap.get(comment.getTbTargetId());
            if (clockin != null) {
                clockin.setTbImageslsList(imagesMap.getOrDefault(
                        clockin.getTbUuid(), Collections.emptyList()));
                comment.setTbPersonClockin(clockin);
            }
        });
    }

    private Map<Integer, TbPersonClockin> batchLoadPersonClockins(List<TbComment> comments) {
        List<Integer> targetIds = comments.stream()
                .map(TbComment::getTbTargetId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (targetIds.isEmpty()) {
            return Collections.emptyMap();
        }

        return tbPersonClockinService.listByIds(targetIds)
                .stream()
                .collect(Collectors.toMap(TbPersonClockin::getTbId, Function.identity()));
    }

    private Map<String, List<TbImagesl>> batchLoadPersonImages(List<String> uuids) {
        if (uuids.isEmpty()) return Collections.emptyMap();

        return tbImageslService.list(new QueryWrapper<TbImagesl>()
                        .in("tb_person_uuid", uuids))
                .stream()
                .collect(Collectors.groupingBy(TbImagesl::getTbPersonUuid));
    }

    private void processType1Comments(List<TbComment> comments) {
        if (comments.isEmpty()) return;

        // 批量获取专项打卡记录
        Map<Integer, TbSpecialClockin> clockinMap = batchLoadSpecialClockins(comments);

        List<Integer> collect = clockinMap.values().stream()
                .map(TbSpecialClockin::getTbId)
                .collect(Collectors.toList());

        // 批量获取专项信息
        Map<Integer, TbSpecial> specialMap = batchLoadSpecials(collect);

        // 批量加载图片
        Map<String, List<TbImagesl>> imagesMap = batchLoadSpecialImages(
                clockinMap.values().stream()
                        .map(TbSpecialClockin::getTbUuid)
                        .collect(Collectors.toList())
        );

        // 关联数据
        comments.forEach(comment -> {
            TbSpecialClockin clockin = clockinMap.get(comment.getTbTargetId());
            if (clockin != null) {
                TbSpecial special = specialMap.get(clockin.getTbId());
                if (special != null) {
                    clockin.setSpecialidName(special.getTbSpecialname());
                }
                clockin.setTbImageslsList(imagesMap.getOrDefault(
                        clockin.getTbUuid(), Collections.emptyList()));
                comment.setTbSpecialClockin(clockin);
            }
        });
    }

    private Map<Integer, TbSpecialClockin> batchLoadSpecialClockins(List<TbComment> comments) {
        List<Integer> targetIds = comments.stream()
                .map(TbComment::getTbTargetId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (targetIds.isEmpty()) return Collections.emptyMap();

        return tbSpecialClockinService.listByIds(targetIds)
                .stream()
                .collect(Collectors.toMap(TbSpecialClockin::getTbId, Function.identity()));
    }

    private Map<Integer, TbSpecial> batchLoadSpecials(List<Integer> specialIds) {
        if (specialIds.isEmpty()) return Collections.emptyMap();

        return tbSpecialService.listByIds(specialIds)
                .stream()
                .collect(Collectors.toMap(TbSpecial::getTbId, Function.identity()));
    }

    private Map<String, List<TbImagesl>> batchLoadSpecialImages(List<String> uuids) {
        if (uuids.isEmpty()) return Collections.emptyMap();

        return tbImageslService.list(new QueryWrapper<TbImagesl>()
                        .in("tb_special_uuid", uuids))
                .stream()
                .collect(Collectors.groupingBy(TbImagesl::getTbSpecialUuid));
    }

    @Override
    public R addComment(TbComment comment,HttpServletRequest request) {
        if (comment.getTbType() == 0) {
            TbPersonClockin byId = tbPersonClockinService.getById(comment.getTbTargetId());
            if (!byId.getTbStatus().equals("0")) {
                return R.error(400,"该打卡审核未通过，无法评论");
            }
        }else{
            TbSpecialClockin byId = tbSpecialClockinService.getById(comment.getTbTargetId());
            if (!byId.getTbStatus().equals("0")) {
                return R.error(400,"该打卡审核未通过，无法评论");
            }
        }

        String tokenFromRequest = JwtUtils.getTokenFromRequest(request);

        String openId = JwtUtils.getOpenId(tokenFromRequest);

        comment.setTbUserId(openId);

        String key = RedisKeyEnum.COMMENT_COOLDOWN + comment.getTbUserId()+":"+comment.getTbTargetId();

        // 检查冷却时间
        String lastCommentTime = (String) redisTemplate.opsForValue().get(key);
        long currentTime = System.currentTimeMillis();
        if (lastCommentTime != null) {
            long last = Long.parseLong(lastCommentTime);
            if (currentTime - last < RedisKeyEnum.COMMENT_COOLDOWN_SECONDS * 1000) {
                return R.error("不能频繁发送！");
            }
        }

        // 新增：检查评论层级
        if (comment.getTbParentId() != 0) {
            TbComment parentComment = baseMapper.selectOne(new QueryWrapper<TbComment>()
                    .eq("tb_comment_id", comment.getTbParentId())
                    .eq("tb_target_status", 1));
            if (parentComment == null) {
                return R.error("父评论不存在或未通过审核");
            }
            if (parentComment.getTbParentId() != 0) {
                return R.error("不能回复二级评论");
            }
        }

        // 保存评论到数据库
        boolean success = save(comment);
        if (success) {
            // 更新冷却时间
            redisTemplate.opsForValue().set(key, String.valueOf(currentTime),
                    RedisKeyEnum.COMMENT_COOLDOWN_SECONDS, TimeUnit.SECONDS);

            long count = this.count(new QueryWrapper<TbComment>().eq("tb_type", comment.getTbType()).eq("tb_target_id", comment.getTbTargetId()));


            // --- 新增：清理当前用户的评论树缓存 ---
            String currentUserId = comment.getTbUserId();

            String cacheKey = RedisKeyEnum.COMMENT_TREE + comment.getTbTargetId()+ ":" + comment.getTbType() + ":" + currentUserId ;

            redisTemplate.delete(cacheKey);

            return R.ok("评论成功").put("count", count);
        } else {
            return R.error("评论失败");
        }
    }

    @Override
    public R auditComment(Integer tbCommentId ,Integer type, Integer status) {
        if (!Arrays.asList(1, 2).contains(status)) {
            return R.error("无效的状态");
        }

        // 添加分布式锁
        String lockKey = RedisKeyEnum.COMMENT_AUDIT + tbCommentId;
        String lockId = UUID.randomUUID().toString();
        try {
            // 尝试获取锁（等待2秒，锁持有10秒）
            Boolean locked = redisTemplate.opsForValue()
                    .setIfAbsent(lockKey, lockId, RedisKeyEnum.LOCKE_TIME, TimeUnit.SECONDS);

            if (!Boolean.TRUE.equals(locked)) {
                return R.error("该评论正在被其他管理员处理");
            }

            // 核心更新逻辑
            UpdateWrapper<TbComment> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("tb_comment_id", tbCommentId)
                    .eq("tb_target_status", 0)
                    .set("tb_target_status", status)
                    .set("tb_update_time", new Date());

            int updated = baseMapper.update(null, updateWrapper);
            if (updated > 0) {
                TbComment comment = baseMapper.selectById(tbCommentId);
                if (status == 1) {
                    clearCommentCache( comment.getTbTargetId(),type);
                }
                return R.ok("审核成功");
            }
            return R.error("评论已被处理或不存在");
        } finally {
            // 释放锁（Lua脚本保障原子性）
            redisTemplate.execute(
                    auditScript,
                    Collections.singletonList(lockKey),
                    lockId
            );
        }
    }

    @Override
    public R getCommentTree(Integer tbTargetId, Integer type , HttpServletRequest request) {



        String currentUserId = getCurrentUserId(request);

        String cacheKey = RedisKeyEnum.COMMENT_TREE + tbTargetId +":" +type + ":" + currentUserId  ;

        try {
            // 缓存逻辑保持不变，但使用新的cacheKey
            String cached = (String) redisTemplate.opsForValue().get(cacheKey);

            if (cached != null) {
                return R.ok().put("data", objectMapper.readValue(cached, new TypeReference<List<CommentDto>>() {}));
            }

            QueryWrapper<TbComment> query = new QueryWrapper<>();
            query.eq("tb_target_id", tbTargetId)  // 必须匹配目标ID
                    .eq("tb_type",type)
                    .and(currentUserId != null, q ->
                            q.eq("tb_target_status", 1)    // 他人评论必须审核通过
                                    .or()                        // 或
                                    .eq("tb_user_id", currentUserId) // 自己的评论（不限审核状态）
                    )
                    .orderByAsc("tb_create_time");    // 按时间排序

            List<TbComment> comments = baseMapper.selectList(query);
            List<CommentDto> tree = buildCommentTree(comments);

            // 设置删除权限
            setDeletePermission(tree, currentUserId);

            // 缓存处理
            redisTemplate.opsForValue().set(cacheKey, objectMapper.writeValueAsString(tree), 1, TimeUnit.HOURS);

            return R.ok().put("data", tree);
        } catch (IOException e) {
            return R.error("数据处理失败");
        }
    }

    @Override
    public R deleteComment(Integer commentId, Integer type , HttpServletRequest request) {
        // 验证用户身份
        String token = JwtUtils.getTokenFromRequest(request);

        String openId = JwtUtils.getOpenId(token);

        // 获取评论信息
        TbComment comment = this.getById(commentId);

        if (comment == null) {
            return R.error("评论不存在");
        }

        // 权限校验
        if (!comment.getTbUserId().equals(openId)) {
            return R.error("无权限删除");
        }

        try {
            // 删除数据库记录
            boolean success = this.removeById(commentId);
            if (!success) {
                return R.error("删除失败");
            }

            // 清除相关缓存（同步Redis）
            clearCommentCache(comment.getTbTargetId(),type);

            return R.ok("删除成功！");
        } catch (Exception e) {
            return R.error("删除过程中发生错误");
        }
    }

    private String getCurrentUserId(HttpServletRequest request) {
        String token = JwtUtils.getTokenFromRequest(request);

        return JwtUtils.getOpenId(token);
    }

    // 设置删除权限（抽离为独立方法）
    private void setDeletePermission(List<CommentDto> comments, String currentUserId) {
        for (CommentDto comment : comments) {
            comment.setDel(comment.getTbUserId().equals(currentUserId));
            if (!comment.getReplies().isEmpty()) {
                comment.getReplies().forEach(reply ->
                        reply.setDel(reply.getTbUserId().equals(currentUserId))
                );
            }
        }
    }

    private List<CommentDto> buildCommentTree(List<TbComment> comments) {
        // 提前返回空列表优化
        if (comments == null || comments.isEmpty()) {
            return Collections.emptyList();
        }

        // 收集需要查询的ID
        Set<String> userIds = new HashSet<>();
        Set<Integer> targetIds = new HashSet<>();
        Set<Integer> personTargets = new HashSet<>();
        Set<Integer> specialTargets = new HashSet<>();

        for (TbComment comment : comments) {
            userIds.add(comment.getTbUserId());
            if (comment.getTbType() == 0) {
                personTargets.add(comment.getTbTargetId());
            } else if (comment.getTbType() == 1) {
                specialTargets.add(comment.getTbTargetId());
            }
            targetIds.add(comment.getTbTargetId());
        }

        // 批量查询关联数据
        Map<String, TbUserInfo> userMap = batchGetUserInfos(userIds);
        Map<Integer, TbPersonClockin> personMap = batchGetPersonClockins(personTargets);
        Map<Integer, TbSpecialClockin> specialMap = batchGetSpecialClockins(specialTargets);

        Map<Long, CommentDto> map = new HashMap<>();
        List<CommentDto> roots = new ArrayList<>();

        // 创建DTO并填充数据
        for (TbComment comment : comments) {
            CommentDto vo = new CommentDto();
            BeanUtils.copyProperties(comment, vo);

            // 填充用户信息
            vo.setTbUserInfo(userMap.getOrDefault(comment.getTbUserId(), null));

            // 根据类型填充打卡信息
            if (comment.getTbType() == 0) {
                vo.setTbPersonClockin(personMap.get(comment.getTbTargetId()));
            } else if (comment.getTbType() == 1) {
                vo.setTbSpecialClockin(specialMap.get(comment.getTbTargetId()));
            }

            map.put(comment.getTbCommentId(), vo);

            if (comment.getTbParentId() == 0) {
                roots.add(vo);
            }
        }
        // 构建层级关系
        for (CommentDto vo : map.values()) {
            if (vo.getTbParentId() != 0) {
                CommentDto parent = map.get(vo.getTbParentId());
                if (parent != null && parent.getTbParentId() == 0) {
                    parent.getReplies().add(vo);
                }
            }
        }
        // 排序优化
        roots.sort(Comparator.comparing(CommentDto::getTbCreateTime));
        return roots;
    }

    // 批量查询用户信息
    private Map<String, TbUserInfo> batchGetUserInfos(Set<String> userIds) {
        if (userIds.isEmpty()) return Collections.emptyMap();

        List<TbUserInfo> users = tbUserService.list(new QueryWrapper<TbUserInfo>().in("tb_wxuuid",userIds));

        return users.stream()
                .collect(Collectors.toMap(TbUserInfo::getTbWxuuid, Function.identity()));
    }

    // 批量查询打卡信息
    private Map<Integer, TbPersonClockin> batchGetPersonClockins(Set<Integer> targetIds) {
        if (targetIds.isEmpty()) return Collections.emptyMap();

        return tbPersonClockinService.listByIds(targetIds)
                .stream()
                .collect(Collectors.toMap(TbPersonClockin::getTbId, Function.identity()));
    }

    // 批量查询特殊打卡信息
    private Map<Integer, TbSpecialClockin> batchGetSpecialClockins(Set<Integer> targetIds) {
        if (targetIds.isEmpty()) return Collections.emptyMap();

        return tbSpecialClockinService.listByIds(targetIds)
                .stream()
                .collect(Collectors.toMap(TbSpecialClockin::getTbId, Function.identity()));
    }

    // 清除缓存方法（独立方法）
    private void clearCommentCache(Integer tbTargetId , int type) {
        String pattern = RedisKeyEnum.COMMENT_TREE + tbTargetId + ":" + type + "*";
        Set<String> keys = redisTemplate.keys(pattern);
        if (keys != null && !keys.isEmpty()) {
            redisTemplate.delete(keys);
        }
    }

}
